package ga;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;

import run.FileWrite;
import function.Function;


public class GA {

	private Function f;
	private int gaSize;
	private int numberIterations;
	private ArrayList<Individual> population;
	private StringBuffer bf = new StringBuffer();

	public GA (Function f, int gaSize, int numberIterations){
		this.f = f;
		this.gaSize = gaSize;
		this.numberIterations = numberIterations;
		createPopulation();
	}

	//criando as populacoes
	private void createPopulation() {
		this.population = new ArrayList<Individual>();
		for (int i = 0; i < this.gaSize; i++) {
			population.add(new Individual(this.f));
		}
	}

	public void run(){
		int iteration = 0;
		ArrayList<Individual> pais;
		ArrayList<Individual> filhos;
		
		while (iteration < numberIterations) {

			//avalia o fitnesse de cada cromossomo
			this.fitnessEvalution(this.population);
			//Ordenacao crescente pelo fitness
			this.sortPopulation(this.population);

			if (iteration % ((this.numberIterations-1)/20) == 0){
				bf.append(this.population.get(0).getFitness() + "\t" + iteration/100 + "\t" + GA_Constants.exp);
				bf.append("\n");
				//System.out.println(this.population.get(0).getFitness());
			}
			//Efetua a selecao dos pais
			//pais = Selection.Roullet(this.population);
			pais = Selection.Roullet(this.population);

			//Cria os filhos dado os pais
			filhos = Recombination.singlePointPais(pais);
			
			//Mutacao dos filhos
			Mutation.doMutation(filhos);

			//Ordenacao dos filhos
			this.fitnessEvalution(filhos);
			this.sortPopulation(filhos);

			//Eletismo
			Elitism.doElitism(this.population);
//			this.population.clear();
			
			//Gerando novo offSpring
			Offspring.Roulette(this.gaSize, filhos, this.population);

			iteration++;
		}
		
		
		try {
			FileWrite.writeInFile(bf.toString(), GA_Constants.ouputFileName);
			FileWrite.writeInFile(this.population.get(0).getFitness() + ", " , GA_Constants.ouputFileNameEnd);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	private void fitnessEvalution(ArrayList<Individual> pop){
		for (Individual id : pop) {
			id.calculateFitness();
		}

	}

	private void sortPopulation(ArrayList<Individual> pop){
		Collections.sort(pop,new ComparatorByBestFitness());
	}

	public ArrayList<Individual> getPopulation(){
		return this.population;
	}

	public int getGASize(){
		return this.gaSize;
	}




}
